import { createContext, useContext, useState, useCallback, useRef } from 'react';
import { useTextRendering } from './TextRenderingContext';
import { getCurrentDPR } from '../components/TextRenderer';

const EditorContext = createContext();

export const useEditor = () => {
  const context = useContext(EditorContext);
  if (!context) {
    throw new Error('useEditor must be used within an EditorProvider');
  }
  return context;
};

export const EditorProvider = ({ children, isReady = false }) => {
  const { fontSize, letterSpacing, measureTextWidth, analyzeTextLineBreaks } = useTextRendering();

  // Editor state
  const [text, setText] = useState('');
  const [cursorPosition, setCursorPosition] = useState(0);
  const [isFocused, setIsFocused] = useState(false);
  
  // Force render trigger
  const [renderTrigger, setRenderTrigger] = useState(0);
  const forceRender = useCallback(() => {
    setRenderTrigger(prev => prev + 1);
  }, []);

  // Helper function to find line boundaries considering \r\n as single units
  const findLineInfo = useCallback((text, position) => {
    const lines = [];
    let currentStart = 0;
    let i = 0;
    
    while (i < text.length) {
      if (text.substring(i, i + 2) === '\r\n') {
        // Found \r\n - treat as single line break
        lines.push({
          start: currentStart,
          end: i,
          text: text.substring(currentStart, i),
          breakType: '\r\n',
          breakLength: 2
        });
        i += 2;
        currentStart = i;
      } else if (text[i] === '\n') {
        // Found \n - single character line break
        lines.push({
          start: currentStart,
          end: i,
          text: text.substring(currentStart, i),
          breakType: '\n',
          breakLength: 1
        });
        i += 1;
        currentStart = i;
      } else {
        i += 1;
      }
    }
    
    // Add final line if there's remaining text
    if (currentStart <= text.length) {
      lines.push({
        start: currentStart,
        end: text.length,
        text: text.substring(currentStart),
        breakType: null,
        breakLength: 0
      });
    }
    
    // Find which line contains the position
    let currentLineIndex = -1;
    let positionInLine = 0;
    
    for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
      const line = lines[lineIndex];
      const lineEndWithBreak = line.end + line.breakLength;
      
      if (position >= line.start && position <= lineEndWithBreak) {
        currentLineIndex = lineIndex;
        positionInLine = position - line.start;
        break;
      }
    }
    
    return {
      lines,
      currentLineIndex,
      positionInLine,
      currentLine: lines[currentLineIndex] || null
    };
  }, []);

  // Handle canvas click for cursor positioning
  const handleCanvasClick = useCallback((e, canvasRef) => {
    if (!isReady) return; // Disable if not ready
    
    const canvas = canvasRef.current;
    const rect = canvas.getBoundingClientRect();
    
    // Get current DPR to adjust coordinates properly
    const dpr = getCurrentDPR();
    
    // Convert client coordinates to canvas coordinates, accounting for DPR
    const x = (e.clientX - rect.left) * dpr;
    const y = (e.clientY - rect.top) * dpr;
    
    const renderLineInfo = analyzeTextLineBreaks(text);
    const navigationLineInfo = findLineInfo(text, cursorPosition);
    let lineY = fontSize + 10;
    
    const spaceWidth = measureTextWidth(' ');
    
    for (let i = 0; i < renderLineInfo.length; i++) {
      const line = renderLineInfo[i];
      if (y < lineY) {
        // Calculate character positions with letter spacing using CanvasKit-style measurement
        let charX = 10;
        const correspondingNavLine = navigationLineInfo.lines[i];
        
        for (let j = 0; j <= line.text.length; j++) {
          if (x < charX) {
            setCursorPosition(correspondingNavLine ? correspondingNavLine.start + j : j);
            break;
          }
          if (j < line.text.length) {
            if (line.text[j] === ' ') {
              charX += spaceWidth;
            } else {
              charX += measureTextWidth(line.text[j]) + letterSpacing;
            }
          }
          if (j === line.text.length) {
            setCursorPosition(correspondingNavLine ? correspondingNavLine.start + j : j);
          }
        }
        break;
      }
      lineY += line.lineHeight;
    }
    
    setIsFocused(true);
  }, [text, fontSize, letterSpacing, measureTextWidth, analyzeTextLineBreaks, findLineInfo, isReady]);

  // Handle keyboard input
  const handleKeyDown = useCallback((e) => {
    if (!isReady || !isFocused) return; // Disable if not ready or not focused
    
    e.preventDefault();
    
    if (e.key === 'Backspace') {
      if (cursorPosition > 0) {
        // Check if we're deleting a \r\n sequence
        if (cursorPosition >= 2 && text.substring(cursorPosition - 2, cursorPosition) === '\r\n') {
          // Delete the entire \r\n sequence
          const newText = text.substring(0, cursorPosition - 2) + text.substring(cursorPosition);
          setText(newText);
          setCursorPosition(cursorPosition - 2);
        } else {
          // Regular single character deletion
          const newText = text.substring(0, cursorPosition - 1) + text.substring(cursorPosition);
          setText(newText);
          setCursorPosition(cursorPosition - 1);
        }
        // Force immediate re-render to update cursor position
        setTimeout(() => forceRender(), 0);
      }
    } else if (e.key === 'Delete') {
      if (cursorPosition < text.length) {
        // Check if we're deleting a \r\n sequence
        if (cursorPosition < text.length - 1 && text.substring(cursorPosition, cursorPosition + 2) === '\r\n') {
          // Delete the entire \r\n sequence
          const newText = text.substring(0, cursorPosition) + text.substring(cursorPosition + 2);
          setText(newText);
        } else {
          // Regular single character deletion
          const newText = text.substring(0, cursorPosition) + text.substring(cursorPosition + 1);
          setText(newText);
        }
        // Force immediate re-render to update cursor position
        setTimeout(() => forceRender(), 0);
      }
    } else if (e.key === 'Enter') {
      // Shift+Enter = line break (\n), Enter = paragraph break (\r\n)
      const lineBreak = e.shiftKey ? '\n' : '\r\n';
      const newText = text.substring(0, cursorPosition) + lineBreak + text.substring(cursorPosition);
      setText(newText);
      setCursorPosition(cursorPosition + lineBreak.length);
      // Force immediate re-render to update cursor position
      setTimeout(() => forceRender(), 0);
    } else if (e.key === 'ArrowLeft') {
      if (e.ctrlKey) {
        // Ctrl+Left: Go to beginning of current line
        const lineInfo = findLineInfo(text, cursorPosition);
        if (lineInfo.currentLine) {
          setCursorPosition(lineInfo.currentLine.start);
        }
      } else {
        // Regular Left: Move one character left, but skip \r\n as a unit
        if (cursorPosition > 0) {
          // Check if we're at the start of a line that was created by \r\n
          if (cursorPosition >= 2 && text.substring(cursorPosition - 2, cursorPosition) === '\r\n') {
            setCursorPosition(cursorPosition - 2);
          } else {
            setCursorPosition(cursorPosition - 1);
          }
        }
      }
    } else if (e.key === 'ArrowRight') {
      if (e.ctrlKey) {
        // Ctrl+Right: Go to end of current line
        const lineInfo = findLineInfo(text, cursorPosition);
        if (lineInfo.currentLine) {
          setCursorPosition(lineInfo.currentLine.end);
        }
      } else {
        // Regular Right: Move one character right, but skip \r\n as a unit
        if (cursorPosition < text.length) {
          // Check if we're about to move over \r\n
          if (cursorPosition < text.length - 1 && text.substring(cursorPosition, cursorPosition + 2) === '\r\n') {
            setCursorPosition(cursorPosition + 2);
          } else {
            setCursorPosition(cursorPosition + 1);
          }
        }
      }
    } else if (e.key === 'ArrowUp') {
      const lineInfo = findLineInfo(text, cursorPosition);
      if (lineInfo.currentLineIndex > 0) {
        const prevLine = lineInfo.lines[lineInfo.currentLineIndex - 1];
        const targetColumn = Math.min(lineInfo.positionInLine, prevLine.text.length);
        setCursorPosition(prevLine.start + targetColumn);
      }
    } else if (e.key === 'ArrowDown') {
      const lineInfo = findLineInfo(text, cursorPosition);
      if (lineInfo.currentLineIndex < lineInfo.lines.length - 1) {
        const nextLine = lineInfo.lines[lineInfo.currentLineIndex + 1];
        const targetColumn = Math.min(lineInfo.positionInLine, nextLine.text.length);
        setCursorPosition(nextLine.start + targetColumn);
      }
    } else if (e.key.length === 1) {
      // Regular character input
      const newText = text.substring(0, cursorPosition) + e.key + text.substring(cursorPosition);
      setText(newText);
      setCursorPosition(cursorPosition + 1);
      // Force immediate re-render to update cursor position
      setTimeout(() => forceRender(), 0);
    }
  }, [isReady, isFocused, cursorPosition, text, forceRender, findLineInfo]);

  // Handle canvas blur
  const handleCanvasBlur = useCallback(() => {
    if (!isReady) return; // Disable if not ready
    setIsFocused(false);
  }, [isReady]);

  // Helper function to get current line and column
  const getCurrentLineAndColumn = useCallback(() => {
    if (!isReady) return { line: 0, column: 0 }; // Return default if not ready
    const beforeCursor = text.substring(0, cursorPosition);
    const lines = beforeCursor.split('\n');
    const currentLine = lines.length - 1;
    const currentColumn = lines[lines.length - 1].length;
    return { line: currentLine, column: currentColumn };
  }, [text, cursorPosition, isReady]);

  // Helper function to get text statistics
  const getTextStats = useCallback(() => {
    if (!isReady) return { lines: 0, words: 0, characters: 0, charactersNoSpaces: 0 }; // Return default if not ready
    const lines = text.split('\n');
    const words = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
    const characters = text.length;
    const charactersNoSpaces = text.replace(/\s/g, '').length;
    
    return {
      lines: lines.length,
      words,
      characters,
      charactersNoSpaces
    };
  }, [text, isReady]);

  // Helper function to insert text at cursor
  const insertText = useCallback((textToInsert) => {
    if (!isReady) return; // Disable if not ready
    const newText = text.substring(0, cursorPosition) + textToInsert + text.substring(cursorPosition);
    setText(newText);
    setCursorPosition(cursorPosition + textToInsert.length);
  }, [text, cursorPosition, isReady]);

  // Helper function to select all text
  const selectAll = useCallback(() => {
    if (!isReady) return; // Disable if not ready
    setCursorPosition(text.length);
    // Note: This is a simplified version. Full text selection would need selection start/end state
  }, [text.length, isReady]);

  // Helper function to clear all text
  const clearText = useCallback(() => {
    if (!isReady) return; // Disable if not ready
    setText('');
    setCursorPosition(0);
  }, [isReady]);

  const value = {
    // Loading state
    isReady,
    
    // Content state
    text,
    setText,
    cursorPosition,
    setCursorPosition,
    isFocused,
    setIsFocused,

    // Render control
    renderTrigger,
    forceRender,

    // Event handlers
    handleCanvasClick,
    handleKeyDown,
    handleCanvasBlur,

    // Helper functions
    getCurrentLineAndColumn,
    getTextStats,
    insertText,
    selectAll,
    clearText,
  };

  return (
    <EditorContext.Provider value={value}>
      {children}
    </EditorContext.Provider>
  );
};
